`include "defines.svh"

module StageID (
    input   logic                           clock,
    input   logic                           reset,

    // StageID -> StageIF
    output  logic                           id2if_allow,
    output  logic [`BJ_BUS_WD-1:0]          bj_bus,

    // StageIF -> StageID
    input   logic                           if2id_fired,
    input   logic [`IF2ID_BUS_WD-1:0]       if2id_bus,

    // StageID -> StageEX
    output  logic                           id2ex_valid,
    output  logic [`ID2EX_BUS_WD-1:0]       id2ex_bus,

    // StageEX -> StageID
    input   logic                           ex2id_allow,

    // StageID -> Regfile
    output  logic [`ID2RF_BUS_WD-1:0]       id2rf_bus,

    // Regfile -> StageID
    input   logic [`RF2ID_BUS_WD-1:0]       rf2id_bus,

    // StageID -> CSR
    output  logic [11:0]                    csr_raddr,

    // CSR -> StageID
    input   logic [63:0]                    csr_rdata,

    // StageEX -> StageID @ Forward & Block
    input   logic [`EX_RF_HZD_BUS_WD-1:0]   ex_rf_hzd_bus,
    input   logic [`EX_CSR_BLK_BUS_WD-1:0]  ex_csr_blk_bus,

    // StageMA -> StageID @ Forward & Block
    input   logic [`MA_RF_HZD_BUS_WD-1:0]   ma_rf_hzd_bus,
    input   logic [`MA_CSR_BLK_BUS_WD-1:0]  ma_csr_blk_bus,

    // StageWB -> StageID @ Forward & Block
    input   logic [`WB_RF_HZD_BUS_WD-1:0]   wb_rf_hzd_bus,
    input   logic [`WB_CSR_BLK_BUS_WD-1:0]  wb_csr_blk_bus,

    // StageID -> StageIF @ Cancel Flag
    output  logic                           id_cancel,

    // CSR -> StageID
    input   logic                           csr_taken,
    input   logic [1:0]                     csr_intr // @ Interrupt
);

    // for debug pipeline
    logic           id_ready;
    logic           id_valid;

    wire [31:0] inst = id_inst;

    wire [63:0] id_next_pc = bj_taken ? bj_target : id_pc_plus_4;


/* ************************* Pipeline ************************* */
    assign id_ready = (~rf_blk) & (~csr_blk);
/* -------------- StageIF <=> StageID -------------- */
    // for debug signal
    logic           icache_miss;
    // to StageID signal
    logic [63:0]    id_pc;
    logic [31:0]    id_inst;
    logic [63:0]    id_pc_plus_4;
    /* verilator lint_off UNUSEDSIGNAL */
    logic [15:0]    if2id_excp_flags;

    logic [`IF2ID_BUS_WD-1:0]   if2id_bus_R;

    assign {
        // for debug
        icache_miss,
        // to StageID
        id_pc,
        id_inst,
        id_pc_plus_4,
        if2id_excp_flags
    } = if2id_bus_R;

    assign  id2if_allow = (!id_valid) | (id_ready & ex2id_allow);
    assign  id2ex_valid = id_valid & id_ready;

    always_ff @ (posedge clock) begin
        if (reset | csr_taken) begin
            id_valid <= 1'b0;
        end
        else if (bj_taken & if2id_fired & id2if_allow) begin
            id_valid <= 1'b0;
        end
        else if (id2if_allow) begin
            id_valid <= if2id_fired;
        end
    end
    always_ff @ (posedge clock) begin
        if (reset) begin
            if2id_bus_R <= `IF2ID_BUS_WD'h0;
        end
        else if (if2id_fired & id2if_allow) begin
            if2id_bus_R <= if2id_bus;
        end
    end
/* -------------- StageIF <=> StageID -------------- */

/* -------------- StageID <=> StageEX -------------- */
    assign id2ex_bus = {
        // for debug
        icache_miss,
        // to StageEX
        id_pc,
        id_inst,
        id_next_pc,
        id_excp_flags,
        id_intr_flags,
        alu_op,
        alu_word,
        alu_unsign,
        alu_mul_signs,
        alu_mul_high,
        alu_src1,
        alu_src2,
        mem_en,
        mem_we,
        mem_op,
        mem_size,
        mem_wdata,
        // to StageMA
        load_sext,
        rf_sel,
        csr_rdata,
        // to Regfile
        rf_we,
        rf_waddr,
        // to CSR
        inst_mret,
        csr_we,
        csr_waddr,
        csr_wdata
    };
/* -------------- StageID <=> StageEX -------------- */
/* ************************* Pipeline ************************* */


/* ************************* Branch & Jump ************************* */
    logic [7:0]     bj_info;
    logic           bj_flag;
    logic [63:0]    bj_target;

    assign bj_info = {
        inst_jalr, inst_jal, inst_bgeu, inst_bltu,
        inst_bge, inst_blt, inst_bne, inst_beq
    };

    BranchJumpUnit bju (
        .pc         (id_pc),
        .rs1        (real_rs1),
        .rs2        (real_rs2),
        .imm        (imm),
        .bj_info    (bj_info),
        .bj_flag    (bj_flag),
        .bj_target  (bj_target)
    );

    wire bj_taken = bj_flag & id_valid &  id_ready;
    wire bj_stall = bj_flag & id_valid & ~id_ready;

    assign bj_bus = { bj_taken, bj_stall, bj_target };
/* ************************* Branch & Jump ************************* */


/* ************************* CSR ************************* */
    wire [63:0] csr_zimm   = { 59'h0, inst[19:15] };
    wire [11:0] csr_addr   = imm_I;

    wire csr_we     = inst_csrrc | inst_csrrs | inst_csrrw
                    | inst_csrrci| inst_csrrsi| inst_csrrwi;
    wire [11:0] csr_waddr  = csr_addr;
    wire [63:0] csr_wdata  = ({64{inst_csrrc }} & (~real_rs1 & csr_rdata))
                           | ({64{inst_csrrs }} & ( real_rs1 | csr_rdata))
                           | ({64{inst_csrrw }} & ( real_rs1            ))
                           | ({64{inst_csrrci}} & (~csr_zimm & csr_rdata))
                           | ({64{inst_csrrsi}} & ( csr_zimm | csr_rdata))
                           | ({64{inst_csrrwi}} & ( csr_zimm            ));

    assign csr_raddr = csr_addr;
/* ---------------------------- CSR Block ---------------------------- */
    // 避免出现前一条指令关闭中断, 下一条指令却产生中断的情况
    wire csr_is_mstatus = ex_csr_waddr == `CSR_ADDR_MSTATUS
                        | ma_csr_waddr == `CSR_ADDR_MSTATUS
                        | wb_csr_waddr == `CSR_ADDR_MSTATUS;
    wire csr_is_mie     = ex_csr_waddr == `CSR_ADDR_MIE
                        | ma_csr_waddr == `CSR_ADDR_MIE
                        | wb_csr_waddr == `CSR_ADDR_MIE;

    logic ex_csr_blk_flag, ma_csr_blk_flag, wb_csr_blk_flag;
    logic [11:0] ex_csr_waddr, ma_csr_waddr, wb_csr_waddr;
    assign { ex_csr_blk_flag, ex_csr_waddr} = ex_csr_blk_bus;
    assign { ma_csr_blk_flag, ma_csr_waddr} = ma_csr_blk_bus;
    assign { wb_csr_blk_flag, wb_csr_waddr} = wb_csr_blk_bus;

    logic ex_csr_blk, ma_csr_blk, wb_csr_blk, csr_blk;
    assign ex_csr_blk = ex_csr_blk_flag & (csr_waddr == ex_csr_waddr | csr_is_mstatus | csr_is_mie);
    assign ma_csr_blk = ma_csr_blk_flag & (csr_waddr == ma_csr_waddr | csr_is_mstatus | csr_is_mie);
    assign wb_csr_blk = wb_csr_blk_flag & (csr_waddr == wb_csr_waddr | csr_is_mstatus | csr_is_mie);
    assign csr_blk = ex_csr_blk | ma_csr_blk | wb_csr_blk;
/* ---------------------------- CSR Block ---------------------------- */
/* ************************* CSR ************************* */


/* **************************************** RegFile **************************************** */
    wire [4:0]  rf_raddr1 = rs1;
    wire [4:0]  rf_raddr2 = rs2;
    assign  id2rf_bus = { rf_raddr1, rf_raddr2 };

    logic [63:0] rf_rdata1;
    logic [63:0] rf_rdata2;
    assign  { rf_rdata1, rf_rdata2 } = rf2id_bus;

    wire rf_we  = U_type       | J_type 
                | I_type_arith | I_type_load | I_type_jump 
                | I_type_csrr  | I_type_csri | R_type_arith;
    wire [4:0] rf_waddr = rd;

    wire read_rs1 = S_type       | B_type      | R_type_arith 
                  | I_type_arith | I_type_load | I_type_jump | I_type_csrr;
    wire read_rs2 = S_type | B_type | R_type_arith ;

    logic ex_rf_blk_flag, ma_rf_blk_flag, wb_rf_blk_flag;
    logic ex_rf_fwd_flag, ma_rf_fwd_flag, wb_rf_fwd_flag;
    logic [4:0] ex_rf_waddr, ma_rf_waddr, wb_rf_waddr;
    logic [63:0] ex_rf_fwd_data, ma_rf_fwd_data, wb_rf_fwd_data;

    wire rf_sel_mem = I_type_load;
    wire rf_sel_csr = I_type_csri | I_type_csrr;
    logic [2:0] rf_sel;
    assign rf_sel[0] = ~ (rf_sel_mem | rf_sel_csr);   // ALU
    assign rf_sel[1] = rf_sel_mem;                       // MEM
    assign rf_sel[2] = rf_sel_csr;                       // CSR

/* ---------------------------- RegFile Forward & Block ---------------------------- */
    assign { ex_rf_blk_flag, ex_rf_fwd_flag, ex_rf_waddr, ex_rf_fwd_data } = ex_rf_hzd_bus;
    assign { ma_rf_blk_flag, ma_rf_fwd_flag, ma_rf_waddr, ma_rf_fwd_data } = ma_rf_hzd_bus;
    assign { wb_rf_blk_flag, wb_rf_fwd_flag, wb_rf_waddr, wb_rf_fwd_data } = wb_rf_hzd_bus;

    wire id_ex_rs1_eq = (rf_raddr1 == ex_rf_waddr);
    wire id_ex_rs2_eq = (rf_raddr2 == ex_rf_waddr);
    wire id_ma_rs1_eq = (rf_raddr1 == ma_rf_waddr);
    wire id_ma_rs2_eq = (rf_raddr2 == ma_rf_waddr);
    wire id_wb_rs1_eq = (rf_raddr1 == wb_rf_waddr);
    wire id_wb_rs2_eq = (rf_raddr2 == wb_rf_waddr);

    // Regfile Block
    logic rf_blk, ex_rf_blk, ma_rf_blk, wb_rf_blk;
    assign ex_rf_blk = ex_rf_blk_flag & (
                        read_rs1 & id_ex_rs1_eq |
                        read_rs2 & id_ex_rs2_eq
                    );
    assign ma_rf_blk = ma_rf_blk_flag & (
                        read_rs1 & id_ma_rs1_eq |
                        read_rs2 & id_ma_rs2_eq
                    );
    assign wb_rf_blk = wb_rf_blk_flag & (
                        read_rs1 & id_wb_rs1_eq |
                        read_rs2 & id_wb_rs2_eq
                    );
    assign rf_blk = ex_rf_blk | ma_rf_blk | wb_rf_blk;

    // Regfile Forward
    logic ex_rs1_fwd, ex_rs2_fwd, ma_rs1_fwd, ma_rs2_fwd, wb_rs1_fwd, wb_rs2_fwd;
    assign ex_rs1_fwd = ex_rf_fwd_flag & read_rs1 & id_ex_rs1_eq;
    assign ex_rs2_fwd = ex_rf_fwd_flag & read_rs2 & id_ex_rs2_eq;
    assign ma_rs1_fwd = ma_rf_fwd_flag & read_rs1 & id_ma_rs1_eq;
    assign ma_rs2_fwd = ma_rf_fwd_flag & read_rs2 & id_ma_rs2_eq;
    assign wb_rs1_fwd = wb_rf_fwd_flag & read_rs1 & id_wb_rs1_eq;
    assign wb_rs2_fwd = wb_rf_fwd_flag & read_rs2 & id_wb_rs2_eq;

    logic [63:0] real_rs1, real_rs2;
    assign real_rs1 = ex_rs1_fwd ? ex_rf_fwd_data
                    : ma_rs1_fwd ? ma_rf_fwd_data
                    : wb_rs1_fwd ? wb_rf_fwd_data
                    : rf_rdata1;
    assign real_rs2 = ex_rs2_fwd ? ex_rf_fwd_data
                    : ma_rs2_fwd ? ma_rf_fwd_data
                    : wb_rs2_fwd ? wb_rf_fwd_data
                    : rf_rdata2;
/* ---------------------------- RegFile Forward & Block ---------------------------- */
/* **************************************** RegFile **************************************** */


/* ************************* Decode ************************* */
    wire [6:0] opcode = inst[6:0];
    wire [2:0] funct3 = inst[14:12];
    wire [6:0] funct7 = inst[31:25];

    wire [4:0] rd  = inst[11:7];
    wire [4:0] rs1 = inst[19:15];
    wire [4:0] rs2 = inst[24:20];
    /* verilator lint_off UNUSEDSIGNAL */
    logic [127:0]   opcodeD;
    logic [7:0]     funct3D;
    logic [127:0]   funct7D;

    wire shift_imm_arith = (inst[31:26] == 6'b010000);
    wire shift_imm_logic = (inst[31:26] == 6'b000000);

    Decoder #(7, 128) opcode_decoder    ( .in (opcode), .out (opcodeD) );
    Decoder #(3, 8  ) funct3_decoder    ( .in (funct3), .out (funct3D) );
    Decoder #(7, 128) funct7_decoder    ( .in (funct7), .out (funct7D) );

    // RV32I
    wire inst_lui       = (opcodeD[7'b0110111]);
    wire inst_auipc     = (opcodeD[7'b0010111]);
    wire inst_jal       = (opcodeD[7'b1101111]);
    wire inst_jalr      = (opcodeD[7'b1100111]);
    wire inst_beq       = (opcodeD[7'b1100011] & funct3D[3'b000]);
    wire inst_bne       = (opcodeD[7'b1100011] & funct3D[3'b001]);
    wire inst_blt       = (opcodeD[7'b1100011] & funct3D[3'b100]);
    wire inst_bge       = (opcodeD[7'b1100011] & funct3D[3'b101]);
    wire inst_bltu      = (opcodeD[7'b1100011] & funct3D[3'b110]);
    wire inst_bgeu      = (opcodeD[7'b1100011] & funct3D[3'b111]);
    wire inst_lb        = (opcodeD[7'b0000011] & funct3D[3'b000]);
    wire inst_lh        = (opcodeD[7'b0000011] & funct3D[3'b001]);
    wire inst_lw        = (opcodeD[7'b0000011] & funct3D[3'b010]);
    wire inst_lbu       = (opcodeD[7'b0000011] & funct3D[3'b100]);
    wire inst_lhu       = (opcodeD[7'b0000011] & funct3D[3'b101]);
    wire inst_sb        = (opcodeD[7'b0100011] & funct3D[3'b000]);
    wire inst_sh        = (opcodeD[7'b0100011] & funct3D[3'b001]);
    wire inst_sw        = (opcodeD[7'b0100011] & funct3D[3'b010]);
    wire inst_addi      = (opcodeD[7'b0010011] & funct3D[3'b000]);
    wire inst_slti      = (opcodeD[7'b0010011] & funct3D[3'b010]);
    wire inst_sltiu     = (opcodeD[7'b0010011] & funct3D[3'b011]);
    wire inst_xori      = (opcodeD[7'b0010011] & funct3D[3'b100]);
    wire inst_ori       = (opcodeD[7'b0010011] & funct3D[3'b110]);
    wire inst_andi      = (opcodeD[7'b0010011] & funct3D[3'b111]);
    wire inst_slli      = (opcodeD[7'b0010011] & funct3D[3'b001] & shift_imm_logic);
    wire inst_srli      = (opcodeD[7'b0010011] & funct3D[3'b101] & shift_imm_logic);
    wire inst_srai      = (opcodeD[7'b0010011] & funct3D[3'b101] & shift_imm_arith);
    wire inst_add       = (opcodeD[7'b0110011] & funct3D[3'b000] & funct7D[7'b0000000]);
    wire inst_sub       = (opcodeD[7'b0110011] & funct3D[3'b000] & funct7D[7'b0100000]);
    wire inst_sll       = (opcodeD[7'b0110011] & funct3D[3'b001] & funct7D[7'b0000000]);
    wire inst_slt       = (opcodeD[7'b0110011] & funct3D[3'b010] & funct7D[7'b0000000]);
    wire inst_sltu      = (opcodeD[7'b0110011] & funct3D[3'b011] & funct7D[7'b0000000]);
    wire inst_xor       = (opcodeD[7'b0110011] & funct3D[3'b100] & funct7D[7'b0000000]);
    wire inst_srl       = (opcodeD[7'b0110011] & funct3D[3'b101] & funct7D[7'b0000000]);
    wire inst_sra       = (opcodeD[7'b0110011] & funct3D[3'b101] & funct7D[7'b0100000]);
    wire inst_or        = (opcodeD[7'b0110011] & funct3D[3'b110] & funct7D[7'b0000000]);
    wire inst_and       = (opcodeD[7'b0110011] & funct3D[3'b111] & funct7D[7'b0000000]);
    // wire inst_fence     = (opcodeD[7'b0001111] & funct3D[3'b000] & funct7D[7'b0000000]);
    // wire inst_fence_i   = (opcodeD[7'b0001111] & funct3D[3'b001] & funct7D[7'b0000000]);
    wire inst_ecall     = (opcodeD[7'b1110011] & funct3D[3'b000] & funct7D[7'b0000000] & rd==0 & rs1==0 & rs2==0);
    wire inst_ebreak    = (opcodeD[7'b1110011] & funct3D[3'b000] & funct7D[7'b0000000] & rd==0 & rs1==0 & rs2==1);
    wire inst_csrrc     = (opcodeD[7'b1110011] & funct3D[3'b011]);
    wire inst_csrrs     = (opcodeD[7'b1110011] & funct3D[3'b010]);
    wire inst_csrrw     = (opcodeD[7'b1110011] & funct3D[3'b001]);
    wire inst_csrrci    = (opcodeD[7'b1110011] & funct3D[3'b111]);
    wire inst_csrrsi    = (opcodeD[7'b1110011] & funct3D[3'b110]);
    wire inst_csrrwi    = (opcodeD[7'b1110011] & funct3D[3'b101]);
    // RV32M
    wire inst_mul       = (opcodeD[7'b0110011] & funct3D[3'b000] & funct7D[7'b0000001]);
    wire inst_mulh      = (opcodeD[7'b0110011] & funct3D[3'b001] & funct7D[7'b0000001]);
    wire inst_mulhsu    = (opcodeD[7'b0110011] & funct3D[3'b010] & funct7D[7'b0000001]);
    wire inst_mulhu     = (opcodeD[7'b0110011] & funct3D[3'b011] & funct7D[7'b0000001]);
    wire inst_div       = (opcodeD[7'b0110011] & funct3D[3'b100] & funct7D[7'b0000001]);
    wire inst_divu      = (opcodeD[7'b0110011] & funct3D[3'b101] & funct7D[7'b0000001]);
    wire inst_rem       = (opcodeD[7'b0110011] & funct3D[3'b110] & funct7D[7'b0000001]);
    wire inst_remu      = (opcodeD[7'b0110011] & funct3D[3'b111] & funct7D[7'b0000001]);
    // RV64I
    wire inst_lwu       = (opcodeD[7'b0000011] & funct3D[3'b110]);
    wire inst_ld        = (opcodeD[7'b0000011] & funct3D[3'b011]);
    wire inst_sd        = (opcodeD[7'b0100011] & funct3D[3'b011]);
    wire inst_addiw     = (opcodeD[7'b0011011] & funct3D[3'b000]);
    wire inst_slliw     = (opcodeD[7'b0011011] & funct3D[3'b001] & shift_imm_logic);
    wire inst_srliw     = (opcodeD[7'b0011011] & funct3D[3'b101] & shift_imm_logic);
    wire inst_sraiw     = (opcodeD[7'b0011011] & funct3D[3'b101] & shift_imm_arith);
    wire inst_addw      = (opcodeD[7'b0111011] & funct3D[3'b000] & funct7D[7'b0000000]);
    wire inst_subw      = (opcodeD[7'b0111011] & funct3D[3'b000] & funct7D[7'b0100000]);
    wire inst_sllw      = (opcodeD[7'b0111011] & funct3D[3'b001] & funct7D[7'b0000000]);
    wire inst_srlw      = (opcodeD[7'b0111011] & funct3D[3'b101] & funct7D[7'b0000000]);
    wire inst_sraw      = (opcodeD[7'b0111011] & funct3D[3'b101] & funct7D[7'b0100000]);
    // RV64M
    wire inst_mulw      = (opcodeD[7'b0111011] & funct3D[3'b000] & funct7D[7'b0000001]);
    wire inst_divw      = (opcodeD[7'b0111011] & funct3D[3'b100] & funct7D[7'b0000001]);
    wire inst_divuw     = (opcodeD[7'b0111011] & funct3D[3'b101] & funct7D[7'b0000001]);
    wire inst_remw      = (opcodeD[7'b0111011] & funct3D[3'b110] & funct7D[7'b0000001]);
    wire inst_remuw     = (opcodeD[7'b0111011] & funct3D[3'b111] & funct7D[7'b0000001]);
    // Other
    wire inst_mret      = (opcodeD[7'b1110011] & funct3D[3'b000] & funct7D[7'b0011000] & rd==0 & rs1==0);
    wire inst_valid     = R_type | I_type | S_type | U_type | B_type | J_type;
/* ************************* Decode ************************* */


/* ************************* Type ************************* */
    // R-type
    wire R_type_arith = inst_add | inst_addw | inst_sub   | inst_subw
                      | inst_and | inst_xor  | inst_or
                      | inst_slt | inst_sltu | inst_sll   | inst_srl   | inst_sra   | inst_sllw | inst_srlw | inst_sraw
                      | inst_mul | inst_mulh | inst_mulhsu| inst_mulhu | inst_mulw
                      | inst_div | inst_divu | inst_divw  | inst_divuw
                      | inst_rem | inst_remu | inst_remw  | inst_remuw ;
    wire R_type_other = inst_mret;
    wire R_type       = R_type_arith | R_type_other;
    // I-type
    wire I_type_arith = inst_addi  | inst_addiw
                      | inst_andi  | inst_ori   | inst_xori
                      | inst_slti  | inst_sltiu
                      | inst_slli  | inst_srli  | inst_srai  | inst_slliw | inst_srliw | inst_sraiw ;
    wire I_type_load  = inst_ld    | inst_lw    | inst_lh    | inst_lb    | inst_lwu   | inst_lhu   | inst_lbu ;
    wire I_type_jump  = inst_jalr;
    wire I_type_csrr  = inst_csrrc | inst_csrrs | inst_csrrw ;
    wire I_type_csri  = inst_csrrci| inst_csrrsi| inst_csrrwi;
    wire I_type_other = inst_ecall | inst_ebreak;
    wire I_type       = I_type_arith | I_type_load | I_type_jump | I_type_csri | I_type_csrr | I_type_other;
    // S-type
    wire S_type       = inst_sd     | inst_sw    | inst_sh    | inst_sb;
    // U-type
    wire U_type       = inst_lui    | inst_auipc;
    // B-type
    wire B_type       = inst_beq    | inst_bne   | inst_blt   | inst_bge   | inst_bltu  | inst_bgeu;
    // J-type
    wire J_type       = inst_jal;
/* ************************* Type ************************* */


/* ************************* Immediate ************************* */
    wire [11:0] imm_I = inst[31:20];
    wire [11:0] imm_S = { inst[31:25], inst[11:7] };
    wire [11:0] imm_B = { inst[31], inst[7], inst[30:25], inst[11:8] };
    wire [19:0] imm_U = inst[31:12];
    wire [19:0] imm_J = { inst[31], inst[19:12], inst[20], inst[30:21] };

    wire [63:0] imm = ({64{I_type}} & { {52{imm_I[11]}}, imm_I       })
                    | ({64{S_type}} & { {52{imm_S[11]}}, imm_S       })
                    | ({64{U_type}} & { {32{imm_U[19]}}, imm_U, 12'b0})
                    | ({64{B_type}} & { {51{imm_B[11]}}, imm_B, 1'b0 })
                    | ({64{J_type}} & { {43{imm_J[19]}}, imm_J, 1'b0 }) ;
/* ************************* Immediate ************************* */


/* ************************* ALU ************************* */
    wire alu_src1_is_pc  = inst_jal | inst_jalr | inst_auipc
                         | inst_beq | inst_bne  | inst_blt
                         | inst_bge | inst_bltu | inst_bgeu;
    wire alu_src1_is_0   = inst_lui ;
    wire alu_src1_is_rs1 = ~(alu_src1_is_pc | alu_src1_is_0);
    wire alu_src2_is_imm = S_type   | U_type | I_type_arith | I_type_load;
    wire alu_src2_is_4   = inst_jal | inst_jalr  ;
    wire alu_src2_is_rs2 = ~(alu_src2_is_imm | alu_src2_is_4);

    logic [11:0] alu_op;
    assign alu_op[ 0] = inst_add   | inst_addi  | inst_addw  | inst_addiw | inst_auipc | inst_lui
                      | inst_ld    | inst_lw    | inst_lh    | inst_lb    | inst_lwu   | inst_lhu   | inst_lbu
                      | inst_sd    | inst_sw    | inst_sh    | inst_sb
                      | inst_beq   | inst_bne   | inst_blt   | inst_bge   | inst_bltu  | inst_bgeu
                      | inst_jal   | inst_jalr;
    assign alu_op[ 1] = inst_sub   | inst_subw;
    assign alu_op[ 2] = inst_slt   | inst_slti  | inst_sltu  | inst_sltiu;
    assign alu_op[ 3] = inst_and   | inst_andi;
    assign alu_op[ 4] = inst_or    | inst_ori;
    assign alu_op[ 5] = inst_xor   | inst_xori;
    assign alu_op[ 6] = inst_sll   | inst_slli  | inst_sllw  |inst_slliw ;
    assign alu_op[ 7] = inst_srl   | inst_srli  | inst_srlw  |inst_srliw;
    assign alu_op[ 8] = inst_sra   | inst_srai  | inst_sraw  |inst_sraiw;
    assign alu_op[ 9] = inst_mul   | inst_mulh  | inst_mulhsu| inst_mulhu | inst_mulw ;
    assign alu_op[10] = inst_div   | inst_divu  | inst_divw  | inst_divuw ;
    assign alu_op[11] = inst_rem   | inst_remu  | inst_remw  | inst_remuw ;

    wire alu_word   = inst_addw  | inst_addiw | inst_subw
                    | inst_sllw  | inst_srlw  | inst_sraw
                    | inst_slliw | inst_srliw | inst_sraiw
                    | inst_mulw  | inst_divw  | inst_divuw | inst_remw  | inst_remuw ;
    wire alu_unsign = inst_sltu  | inst_sltiu 
                    | inst_divu  | inst_divuw 
                    | inst_remu  | inst_remuw;
    wire [1:0] alu_mul_signs = {2{(inst_mul | inst_mulh | inst_mulw)}} & 2'b11
                             | {2{(inst_mulhsu)}}                      & 2'b10
                             | {2{(inst_mulhu)}}                       & 2'b00 ;
    wire alu_mul_high = inst_mulh | inst_mulhsu | inst_mulhu;

    wire [63:0] alu_src1 = {64{alu_src1_is_rs1}} & real_rs1
                         | {64{alu_src1_is_pc }} & id_pc
                         | {64{alu_src1_is_0  }} & 64'h0;
    wire [63:0] alu_src2 = {64{alu_src2_is_rs2}} & real_rs2
                         | {64{alu_src2_is_imm}} & imm
                         | {64{alu_src2_is_4  }} & 64'h4;
/* ************************* ALU ************************* */


/* ************************* MEM ************************* */
    logic [3:0] mem_op;
    assign mem_op[0] = inst_sb  | inst_lb   | inst_lbu ;
    assign mem_op[1] = inst_sh  | inst_lh   | inst_lhu ;
    assign mem_op[2] = inst_sw  | inst_lw   | inst_lwu ;
    assign mem_op[3] = inst_sd  | inst_ld              ;

    wire mem_en   = |mem_op;
    wire mem_we   = inst_sd  | inst_sw   | inst_sh  | inst_sb;
    wire [2:0] mem_size = ({3{mem_op[3]}}) & 3'b011
                        | ({3{mem_op[2]}}) & 3'b010
                        | ({3{mem_op[1]}}) & 3'b001
                        | ({3{mem_op[0]}}) & 3'b000 ;
    wire load_sext =    inst_lw   | inst_lh   | inst_lb ;
    wire [63:0] mem_wdata = real_rs2;
/* ************************* MEM ************************* */


/* ************************************* Trap ************************************* */
    logic [15:0] id_excp_flags;
    assign id_excp_flags[1:0]   = if2id_excp_flags[1:0];
    assign id_excp_flags[2]     = id_valid & (~|if2id_excp_flags[1:0])  & ~inst_valid;
    assign id_excp_flags[3]     = id_valid & (~|if2id_excp_flags[2:0])  &  inst_ebreak;
    assign id_excp_flags[10:4]  = 7'b0;
    assign id_excp_flags[11]    = id_valid & (~|if2id_excp_flags[10:0]) & inst_ecall;
    assign id_excp_flags[15:12] = 4'b0;

    logic [15:0] id_intr_flags;
    assign id_intr_flags[2:0] = 3'b0;
    assign id_intr_flags[3] = csr_intr[0] & (~csr_blk); // 避免错误地标记中断
    assign id_intr_flags[6:4] = 3'b0;
    assign id_intr_flags[7] = csr_intr[1] & (~csr_blk); // 避免错误地标记中断
    assign id_intr_flags[15:8] = 8'b0;

/* ----------------------------- Cancel Flag ----------------------------- */
    assign id_cancel = id_valid & ((|id_excp_flags) | (|id_intr_flags) | inst_mret);
/* ----------------------------- Cancel Flag ----------------------------- */
/* ************************************* Trap ************************************* */

endmodule
